#include <libemb/BaseType.h>
#include <libemb/Tracer.h>
#include <libemb/ArgUtil.h>
#include <libemb/Thread.h>
#include <libemb/DateTime.h>

using namespace libemb;

class MultiThread:public Threading{
private:
    bool m_stopFlag{false};
    bool m_quit[6]{false,false,false,false,false,false};
public:
    MultiThread()
    {
        char* args = "hello";
        threading(&MultiThread::threadA1,this);
        threading(&MultiThread::threadA2,this,args);
        threading(&MultiThread::threadC,this,args,std::string("world from threading!"));

        pthreading(&MultiThread::threadB1,this);
        pthreading(&MultiThread::threadB2,this,args);
        pthreading(&MultiThread::threadC,this,args,std::string("world from pthreading!"));  
    }
    void stopAll()
    {
        m_stopFlag = true;
        while(1)
        {
            if (m_quit[0] && m_quit[1] && m_quit[2] && m_quit[3])
            {
                break;
            }
            Thread::msleep(100);
        }
    }
private:
    void threadA1()
    {
        while(!m_stopFlag)
        {
            Thread::msleep(1000);
            TRACE_DBG_CLASS("run threadA1().");
        }
        m_quit[0]=true;
    }
    void threadA2(void* args)
    { 
        while(!m_stopFlag)
        {
            Thread::msleep(1000);
            TRACE_DBG_CLASS("run threadA2(\"%s\").",args);
        }
        m_quit[1]=true;
    }
    void threadB1()
    {
        while(!m_stopFlag)
        {
            Thread::msleep(1000);
            TRACE_DBG_CLASS("run threadB1().");
        }
        m_quit[2]=true;
    }
    void threadB2(void* args)
    {
        while(!m_stopFlag)
        {
            Thread::msleep(1000);
            TRACE_DBG_CLASS("run threadB2(\"%s\").",args);
        }
        m_quit[3]=true;
    }
    void threadC(void* args,std::string info)
    {
        while(!m_stopFlag)
        {
            Thread::msleep(1000);
            TRACE_DBG_CLASS("run threadC(\"%s\",\"%s\").",args,VSTR(info));
            break;
        }
    }
};

class MyTask:public Runnable{
public:
    void run(Thread& thread)
    {
        while(thread.isRunning())
        {
            TRACE_DBG_CLASS("My Task run in thread: 0x%08x",&thread);
            Thread::msleep(1000);
        }
    }
};


void testThread(void)
{
    std::unique_ptr<MultiThread> thread = nullptr;
    auto& pool = ThreadPool::getInstance();
    MyTask task;
    Thread proto;
    pool.init(proto,5);
    while(1)
    {
        TRACE_CYAN("====Test Thread====");
        TRACE_CYAN("01. start Threading.");
        TRACE_CYAN("02. stop Threading.");
        TRACE_CYAN("03. start Thread pool.");
        TRACE_CYAN("04. stop Thread poolp.");
        TRACE_CYAN("q . quit.");
        InputReader reader;
		reader.waitInput();
        if (reader.isString("q") || reader.isString("quit")) 
        {
            break;
        }
        else if(reader.isString("01"))
        {
            thread = std::make_unique<MultiThread>();
        }
        else if(reader.isString("02"))
        {
            thread->stopAll();
        }
        else if(reader.isString("03"))
        {
            for(int i=0; i<5; i++)
            {
                int id = pool.start(task);
                TRACE_INFO("start thread id: %d",id);
            }
        }
        else if(reader.isString("04"))
        {
            for(int i=0; i<5; i++)
            {
                pool.cancel(i);
                TRACE_INFO("stop thread id: %d",i);
            }
        }
    }
}

